package com.jxw.test.application.base.strategy;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import com.jxw.test.application.base.strategy.annotation.Strategy;
import com.jxw.test.application.base.strategy.handler.BaseStrategyHandler;
import com.jxw.test.application.base.strategy.utils.SpelUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 策略选择器
 */
@Component
public class StrategySelector {


    /**
     * 策略类型与处理器对象集合的映射关系
     *
     * key - 策略类型枚举对象
     * value - 处理器对象集合
     *
     * 示例
     * {
     *     DEVICE_BIND: [DeviceBindStrategyHandler,DeviceBindStrategyHandler2,DeviceBindStrategyHandler3,....]
     * }
     *
     */
    private static Map<StrategyType, List<BaseStrategyHandler<?,?>>> strategyTypeListMap = new ConcurrentHashMap<>();

    /**
     * 注入所有的策略处理器对象
     */
    @Autowired(required = false)
    private List<BaseStrategyHandler> strategyHandlers;

    /**
     * Bean初始化方法 加载所有策略处理器
     */
    @PostConstruct
    public void init(){
        if (ObjectUtil.isEmpty(strategyHandlers)) return;

        strategyTypeListMap = strategyHandlers.stream()
                .filter(strategyHandler -> AnnotationUtil.hasAnnotation(strategyHandler.getClass(), Strategy.class))
                .collect(Collectors.toMap(
                    strategyHandler -> {
                        //获得策略注解
                        Strategy strategyAnnotation = AnnotationUtil.getAnnotation(strategyHandler.getClass(), Strategy.class);
                        return strategyAnnotation.type();
                    },
                    strategyHandler -> ListUtil.toList(strategyHandler),
                    (handlers1, handlers2) -> CollUtil.addAllIfNotContains(handlers1, handlers2)
                ));
    }

    /**
     * 根据策略获取对应的处理器对象
     * @return
     * @param
     */
    public static <T> BaseStrategyHandler getStrategyHandler(T data, StrategyType strategyType){
        if (ObjectUtil.isEmpty(strategyType)) {
            throw new RuntimeException("参数：strategyType，策略类型不能为空！");
        }

        //根据策略类型，获取该类型的处理器集合
        List<BaseStrategyHandler<?, ?>> baseStrategyHandlers = strategyTypeListMap.get(strategyType);
        if (ObjectUtil.isEmpty(baseStrategyHandlers)) {
            throw new RuntimeException("未找到策略" + strategyType + "对应的处理器！");
        }

        BaseStrategyHandler handler = null;
        //默认处理器
        BaseStrategyHandler defaultHandler = null;

        //循环判断各个处理器
        for (BaseStrategyHandler<?, ?> baseStrategyHandler : baseStrategyHandlers) {
            //获取处理器上策略注解
            Strategy strategy = AnnotationUtil.getAnnotation(baseStrategyHandler.getClass(), Strategy.class);
            //获取策略注解的表达式
            String el = strategy.el();
            //设置默认策略处理器
            if ("default".equals(el)) {
                defaultHandler = baseStrategyHandler;
                continue;
            }
            
            //解析Spel表达式
            Boolean flag = SpelUtils.parseExpression(el, data, Boolean.class, false);
            if (flag) {
                handler = baseStrategyHandler;
            }
        }

        return ObjectUtil.isNull(handler) ? defaultHandler : handler;
    }
}
